using Datacollection.Data.Models;
using Datacollection.DataProcessing;
using Datacollection.Mes1;
using Datacollection.Models;
using Datacollection.Services.Logging;
using Datacollection.Services.Storage;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Org.BouncyCastle.Crypto.Tls;
using SerialDataCollector.Services.Communication;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Runtime.CompilerServices.RuntimeHelpers;

namespace Datacollection
{
    public partial class Form1 : Form
    {
        private readonly TestDataParser _dataParser;
        private readonly TestDataFileSaver _fileSaver;
        // 串口通信实例
        private SerialCommunicator _serialCommunicator;
        // 扫描状态标记
        private bool _isWaitingForScan = false;
        private string _scannedBarcode = string.Empty;
        private bool _isProcessingTest = false;
        //串口配置参数（可从配置文件读取）
        private string _portName;
        private int _baudRate;
        private Parity _parity;
        private int _dataBits;
        private StopBits _stopBits;
        int count = 0;
        int okcount = 0;
        int nocount = 0;
        string url = "http//111";

        // 保存当前配置（避免频繁读取配置文件）
        private AppSettings _currentSettings;
        public Form1()
        {
            InitializeComponent();
            _dataParser = new TestDataParser();
            _fileSaver = new TestDataFileSaver();
            InitializeDataGridView();
            // 加载配置
            LoadSettings();
            // 状态栏显示当前配置
            UpdateStatusBarWithSettings();
            InitUIState();

        }


        private void Form1_Load(object sender, EventArgs e)
        {
            var config = LoadSerialConfig();

            //解析返回的参数（按顺序对应：PortName, BaudRate, DataBits, Parity, StopBits）
            _portName = (string)config[0];
            _baudRate = (int)config[1];
            _dataBits = (int)config[2];
            _parity = (Parity)config[3];
            _stopBits = (StopBits)config[4];
        }

        /// <summary>
        /// 加载保存的串口配置文件，返回解析后的串口参数
        /// </summary>
        /// <param name="defaultPort">默认串口号（文件不存在或解析失败时使用）</param>
        /// <param name="defaultBaud">默认波特率</param>
        /// <param name="defaultDataBits">默认数据位</param>
        /// <param name="defaultParity">默认校验位</param>
        /// <param name="defaultStopBits">默认停止位</param>
        /// <returns>解析后的串口参数（数组顺序：PortName, BaudRate, DataBits, Parity, StopBits）</returns>
        private object[] LoadSerialConfig(
            string defaultPort = "COM1",
            int defaultBaud = 115200,
            int defaultDataBits = 8,
            Parity defaultParity = Parity.None,
            StopBits defaultStopBits = StopBits.One)
        {
            try
            {
                // 1. 确定配置文件路径（程序运行目录下的 Config\serial_config.txt）
                // 获取程序运行目录（通常为 bin\Debug 或 bin\Release）
                string appPath = Application.StartupPath; // 需引用 System.Windows.Forms
                                                          // 拼接 Config 文件夹路径
                                                          // 拼接完整配置文件路径
                string configPath = Path.Combine(appPath, "serial_config.txt");


                // 2. 检查文件是否存在
                if (!File.Exists(configPath))
                {
                    Console.WriteLine($"配置文件不存在：{configPath}，使用默认参数");
                    return new object[] { defaultPort, defaultBaud, defaultDataBits, defaultParity, defaultStopBits };
                }

                // 3. 读取文件内容
                string[] lines = File.ReadAllLines(configPath);
                string portName = defaultPort;
                int baudRate = defaultBaud;
                int dataBits = defaultDataBits;
                Parity parity = defaultParity;
                StopBits stopBits = defaultStopBits;

                // 4. 解析每一行键值对
                foreach (string line in lines)
                {
                    if (string.IsNullOrWhiteSpace(line)) continue; // 跳过空行

                    // 分割键值对（只按第一个等号分割，避免值中包含等号）
                    int equalsIndex = line.IndexOf('=');
                    if (equalsIndex <= 0 || equalsIndex >= line.Length - 1)
                    {
                        Console.WriteLine($"无效的配置格式：{line}，跳过此行");
                        continue;
                    }

                    string key = line.Substring(0, equalsIndex).Trim();
                    string value = line.Substring(equalsIndex + 1).Trim();

                    // 根据键解析值
                    switch (key)
                    {
                        case "PortName":
                            portName = value; // 串口号直接赋值（无需转换）
                            break;
                        case "BaudRate":
                            // 波特率转换为整数
                            if (int.TryParse(value, out int baud))
                                baudRate = baud;
                            else
                                Console.WriteLine($"波特率格式错误：{value}，使用默认值");
                            break;
                        case "DataBits":
                            // 数据位转换为整数（5-8）
                            if (int.TryParse(value, out int db) && db >= 5 && db <= 8)
                                dataBits = db;
                            else
                                Console.WriteLine($"数据位格式错误：{value}，使用默认值");
                            break;
                        case "Parity":
                            // 校验位转换为枚举
                            if (Enum.TryParse<Parity>(value, out Parity p))
                                parity = p;
                            else
                                Console.WriteLine($"校验位格式错误：{value}，使用默认值");
                            break;
                        case "StopBits":
                            // 停止位转换为枚举
                            if (Enum.TryParse<StopBits>(value, out StopBits sb))
                                stopBits = sb;
                            else
                                Console.WriteLine($"停止位格式错误：{value}，使用默认值");
                            break;
                        default:
                            Console.WriteLine($"未知配置项：{key}，忽略");
                            break;
                    }
                }

                // 5. 输出加载结果
                Console.WriteLine($"配置加载成功：");
                Console.WriteLine($"串口号：{portName}，波特率：{baudRate}，数据位：{dataBits}");
                Console.WriteLine($"校验位：{parity}，停止位：{stopBits}");

                return new object[] { portName, baudRate, dataBits, parity, stopBits };
            }
            catch (IOException ex)
            {
                Console.WriteLine($"文件读取错误：{ex.Message}，使用默认参数");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"加载配置失败：{ex.Message}，使用默认参数");

            }
            // 异常情况下返回默认值
            return new object[] { defaultPort, defaultBaud, defaultDataBits, defaultParity, defaultStopBits };
        }



        //初始化测试按钮
        private void InitUIState()
        {
            btnStartTest.Enabled = true;
            btnStopTest.Enabled = false;
            statusLabel.Text = "就绪：点击开始测试";
            txtBarcode.Text = string.Empty;
        }

        #region 加载设置文件
        

        // 加载配置（从应用程序设置读取）
        private void LoadSettings()
        {
            _currentSettings = new AppSettings
            {
                mo_id = Properties.Settings.Default.mo_id,
                machineSN = Properties.Settings.Default.machineSN,
                partID = Properties.Settings.Default.partID,
                deptID = Properties.Settings.Default.deptID,
                lineID = Properties.Settings.Default.lineID,
                test_Station = Properties.Settings.Default.test_Station,
                tosMasterId = Properties.Settings.Default.tosMasterId,
                testChannelID = Properties.Settings.Default.testchannelID,
                UsedCount = Properties.Settings.Default.UsedCount,
                SavePath = Properties.Settings.Default.SavePath,
                SerialRetryCount = Properties.Settings.Default.SerialRetryCount,
                AutoSaveData = Properties.Settings.Default.AutoSaveData,
            };



            // 如果是首次使用，设置默认保存路径
            if (string.IsNullOrWhiteSpace(_currentSettings.SavePath))
            {
                _currentSettings.SavePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TestData");
                Properties.Settings.Default.SavePath = _currentSettings.SavePath;
                Properties.Settings.Default.Save();
            }

            // 更新文件保存服务的路径（如果需要）
            _fileSaver.UpdateSavePath(_currentSettings.SavePath);
        }


        // 状态栏显示当前配置摘要
        private void UpdateStatusBarWithSettings()
        {
            idWork_txb.Text = _currentSettings.mo_id;
            idFixture_txb.Text = _currentSettings.tosMasterId;
            alreadyUsed_txb.Text = _currentSettings.UsedCount.ToString();
        }

        // 打开设置窗体的按钮点击事件
        private void btnOpenSettings_Click(object sender, EventArgs e)
        {
            using (var settingsForm = new Setup())
            {
                // 显示设置窗体，等待用户操作
                if (settingsForm.ShowDialog() == DialogResult.OK)
                {
                    // 用户点击了保存，重新加载配置
                    LoadSettings();
                    // 更新主窗体显示
                    UpdateStatusBarWithSettings();
                    LogServiceLocator.Logger.Info("配置已更新并应用");
                }
            }
        }

        // 打开串口设置窗体的按钮点击事件
        private void SPsettings_Click(object sender, EventArgs e)
        {
            using (var configForm = new SPsettings())
            {
                // 【关键】传递当前配置（从主窗口变量或配置文件读取）
                configForm.PortName = _portName;   // 假设主窗口有变量存储当前配置
                configForm.BaudRate = _baudRate;
                configForm.DataBits = _dataBits;
                configForm.Parity = _parity;
                configForm.StopBits = _stopBits;

                // 显示对话框，等待用户操作
                if (configForm.ShowDialog() == DialogResult.OK)
                {
                    // 1. 读取新配置（设置窗体的公共属性）
                    string newPort = configForm.PortName;
                    int newBaud = configForm.BaudRate;
                    Parity newParity = configForm.Parity;
                    int newDataBits = configForm.DataBits;
                    StopBits newStopBits = configForm.StopBits;

                    // 2. 更新主窗口的配置变量
                    _portName = newPort;
                    _baudRate = newBaud;
                    _dataBits = newDataBits;
                    _parity = newParity;
                    _stopBits = newStopBits;

                    // 3. 保存到配置文件（持久化，下次启动生效）
                    SaveConfigToFile(newPort, newBaud, newDataBits, newParity, newStopBits);

                    // 4. 更新主窗口显示
                    statusLabel.Text = $"串口配置已更新：{newPort} {newBaud}";
                }
            }
        }
        private bool SaveConfigToFile(string newPort, int newBaud, int newDataBits,
                             Parity newParity, StopBits newStopBits)
        {
            try
            {
                // 1. 确定保存路径（用户目录下的应用程序文件夹）
                string appDataPath = Application.StartupPath;
                // 保存到程序运行目录（需注意权限，如Program Files下可能无法写入）

                string configPath = Path.Combine(appDataPath, "serial_config.txt");


                // 3. 组织配置内容（键值对格式，便于读取）
                string configContent = $"PortName={newPort}\r\n" +
                                      $"BaudRate={newBaud}\r\n" +
                                      $"DataBits={newDataBits}\r\n" +
                                      $"Parity={newParity.ToString()}\r\n" +
                                      $"StopBits={newStopBits.ToString()}\r\n";

                // 4. 写入文件（覆盖原有内容）
                File.WriteAllText(configPath, configContent);

                // 5. 调试信息
                Console.WriteLine($"配置已保存到: {configPath}");
                return true;
            }
            catch (IOException ex)
            {
                Console.WriteLine($"文件操作错误: {ex.Message}");
                return false;
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($"权限不足: {ex.Message}");
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"保存配置失败: {ex.Message}");
                return false;
            }
        }

        #endregion

        #region 操作DataGridView
        // 初始化DataGridView列（确保列名与DataTable完全一致）
        private void InitializeDataGridView()
        {
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.Columns.Clear();

            // 测试ID列
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "TestId", // 与DataTable列名一致
                HeaderText = "测试ID",
                Width = 120
            });

            // 测试类型列
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "TestType", // 与DataTable列名一致
                HeaderText = "测试类型",
                Width = 130
            });

            // 通道列
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Channels", // 与DataTable列名一致
                HeaderText = "通道",
                Width = 130
            });

            // 测量值列
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Value", // 与DataTable列名一致
                HeaderText = "测量值",
                Width = 170
            });

            // 状态列（关键：确保DataPropertyName为"Status"）
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "Status", // 与DataTable列名严格一致
                HeaderText = "状态",
                Width = 130
            });

            // 样式设置
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.ReadOnly = true;
            dataGridView1.RowHeadersVisible = false;
            dataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
        }

        // 显示测试结果到DataGridView
        public void DisplayTestResults(string rawData)
        {
            if (string.IsNullOrEmpty(rawData))
            {
                LogServiceLocator.Logger.Warn("尝试显示空的测试数据");
                return;
            }

            try
            {
                TestSummary summary = _dataParser.Parse(rawData);
                DataTable dataTable = ConvertToDataTable(summary);
                ValidateDataTableColumns(dataTable);

                // 更新UI
                if (dataGridView1.InvokeRequired)
                {
                    dataGridView1.Invoke(new Action(() => UpdateGridDataSource(dataTable)));
                }
                else
                {
                    UpdateGridDataSource(dataTable);
                }


                //自动保存按钮为true时，保存测试数据
                if (_currentSettings.AutoSaveData)
                {
                    string savedPath = _fileSaver.SaveTestData(summary);
                    if (!string.IsNullOrEmpty(savedPath))
                    {
                        //显示保存成功信息
                        MessageBox.Show($"测试数据已保存到: {savedPath}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
            }
            catch (Exception ex)
            {
                LogServiceLocator.Logger.Error("显示和保存测试结果失败", ex);
                MessageBox.Show($"处理数据时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }


        }

        private void ValidateDataTableColumns(DataTable table)
        {
            string[] requiredColumns = { "TestId", "TestType", "Channels", "Value", "Status" };
            foreach (string col in requiredColumns)
            {
                if (!table.Columns.Contains(col))
                {
                    throw new Exception($"数据表格缺少必要的列: {col}");
                }
            }
        }

        // 更新DataGridView数据源并高亮失败项
        private void UpdateGridDataSource(DataTable dataTable)
        {
            dataGridView1.DataSource = null; // 先清空旧数据
            dataGridView1.DataSource = dataTable;
            HighlightFailedRows();
        }

        // 转换为DataTable（确保列名正确）
        private DataTable ConvertToDataTable(TestSummary summary)
        {
            DataTable table = new DataTable();

            // 明确添加所有列（与DataGridView的DataPropertyName严格匹配）
            table.Columns.Add("TestId", typeof(int));
            table.Columns.Add("TestType", typeof(string));
            table.Columns.Add("Channels", typeof(string));
            table.Columns.Add("Value", typeof(string));
            table.Columns.Add("Status", typeof(string)); // 关键：确保列名为"Status"

            foreach (var testItem in summary.TestItems)
            {
                DataRow row = table.NewRow();

                // 为每行数据赋值（确保Status列被正确填充）
                switch (testItem)
                {
                    case DcrTestResult dcr:
                        row["TestId"] = dcr.TestId;
                        row["TestType"] = dcr.TestType;
                        row["Channels"] = $"{dcr.Channel1}-{dcr.Channel2}";
                        row["Value"] = $"{dcr.Value}{dcr.Unit}";
                        row["Status"] = dcr.Status; // 确保赋值给Status列
                        break;

                    case IwTestResult iw:
                        row["TestId"] = iw.TestId;
                        row["TestType"] = iw.TestType;
                        row["Channels"] = $"{iw.Channel1}-{iw.Channel2}";
                        row["Value"] = $"{iw.Value1}, {iw.Value2}";
                        row["Status"] = (iw.Status1 == "OK" && iw.Status2 == "OK") ? "OK" : "NG";
                        break;

                    case IrHipotTestResult ir:
                        row["TestId"] = ir.TestId;
                        row["TestType"] = ir.TestType;
                        row["Channels"] = $"{ir.Channel1}, {ir.Channel2}";
                        row["Value"] = $"{ir.Value}{ir.Unit}";
                        row["Status"] = ir.Status; // 确保赋值给Status列
                        break;
                }

                table.Rows.Add(row);
            }

            return table;
        }

        // 高亮失败行（使用列索引避免列名依赖）
        private void HighlightFailedRows()
        {
            // 找到Status列的索引（避免直接使用列名）
            int statusColumnIndex = -1;
            for (int i = 0; i < dataGridView1.Columns.Count; i++)
            {
                if (dataGridView1.Columns[i].DataPropertyName == "Status")
                {
                    statusColumnIndex = i;
                    break;
                }
            }

            if (statusColumnIndex == -1)
            {
                LogServiceLocator.Logger.Warn("未找到Status列，无法高亮失败行");
                return;
            }

            // 遍历行设置样式
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                if (row.Cells[statusColumnIndex].Value == null) continue;

                string status = row.Cells[statusColumnIndex].Value.ToString().Trim();
                if (status != "OK" && !string.IsNullOrEmpty(status))
                {
                    row.DefaultCellStyle.ForeColor = System.Drawing.Color.White;
                    row.DefaultCellStyle.BackColor = System.Drawing.Color.Red;
                }
            }
        }

        #endregion

        #region 测试流程
        // 开始按钮点击事件
        /// <summary>
        /// 开始测试按钮点击事件（适配键盘模式扫描枪）
        /// 流程：连接串口 → 光标定位到文本框 → 等待扫码（键盘输入） → 发送命令 → 接收数据 → 数据处理→ 上传mes
        /// </summary>
        private async void start_btn_Click(object sender, EventArgs e)
        {
            // 获取日志实例
            var logger = LogServiceLocator.Logger;

            //设置基本参数
            if (string.IsNullOrEmpty(Properties.Settings.Default.mo_id))
            {
                MessageBox.Show("工单号不能为空，请先设置！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (string.IsNullOrEmpty(Properties.Settings.Default.machineSN))
            {
                MessageBox.Show("设备条码不能为空，请先设置！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (string.IsNullOrEmpty(Properties.Settings.Default.partID))
            {
                MessageBox.Show("料号不能为空，请先设置！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            if (string.IsNullOrEmpty(Properties.Settings.Default.lineID))
            {
                MessageBox.Show("线别不能为空，请先设置！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            if (string.IsNullOrEmpty(Properties.Settings.Default.test_Station))
            {
                MessageBox.Show("站位代码不能为空，请先设置！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            // 重置状态
            ResetTestState();
            btnStartTest.Enabled = false;
            btnStopTest.Enabled = true;
            statusLabel.Text = "正在初始化...";
            logger.Info("===== 开始新的测试流程 =====");
            logger.Debug("测试按钮被点击，初始化状态变量");

            // 创建取消令牌（用于超时和手动停止）
            var cts = new CancellationTokenSource();

            try
            {
                // 1. 连接串口
                logger.Debug("开始连接串口...");
                if (!await ConnectToSerialPort())
                {
                    statusLabel.Text = "串口连接失败，请检查配置";
                    logger.Error("串口连接失败，终止测试流程");
                    ResetTestState();
                    return;
                }
                logger.Info("串口连接成功");

                // 2. 等待扫描枪信号（键盘模式）
                statusLabel.Text = "等待扫描枪...请扫描条码";
                txtBarcode.Text = ""; // 清空文本框
                txtBarcode.ImeMode = System.Windows.Forms.ImeMode.Disable;//强制把输入法切成英文输入
                txtBarcode.Focus();   // 强制光标定位到文本框
                logger.Debug("等待扫描枪输入（30秒超时），已将光标定位到条码输入框");
                bool scanSuccess = await WaitForKeyboardScan(30000, cts.Token); // 30秒超时

                if (!scanSuccess)
                {
                    statusLabel.Text = "扫描超时或取消";
                    logger.Warn("扫描操作超时或被取消");
                    ResetTestState();
                    return;
                }

                // 3. 扫码成功，显示条码并发送测试命令
                string barcode = txtBarcode.Text.Trim();
                Properties.Settings.Default.barcode = barcode;
                statusLabel.Text = $"已扫描：{barcode}，发送测试命令...";
                logger.Info($"扫描成功，条码内容：{barcode}，准备发送测试命令");
                _serialCommunicator.SendData("TRIGger:SOURce BUS\n");
                bool commandSent = _serialCommunicator.SendData("*TRG\n");
                if (!commandSent)
                {
                    statusLabel.Text = "发送测试命令失败";
                    logger.Error("测试命令发送失败");
                    ResetTestState();
                    return;
                }

                // 4. 等待机器返回测试数据
                statusLabel.Text = "等待机器测试完成...";
                _isProcessingTest = true;
                logger.Debug("开始等待机器返回测试数据（60秒超时）");
                // 60秒超时
                string machineData = await WaitForMachineTestData(60000, cts.Token);


                //合格数显示
                if (machineData.Contains("FAIL"))
                {
                    count += 1;
                    nocount += 1;
                }
                else
                {
                    count += 1;
                    okcount += 1;
                }
                totalTest_txb.Text = count.ToString();
                dispassItem_txb.Text = nocount.ToString();
                passItem_txb.Text = okcount.ToString();
                passRate_txb.Text = (okcount * 100 / count).ToString() + "%";

                if (string.IsNullOrEmpty(machineData))
                {
                    statusLabel.Text = "未收到机器数据，超时";
                    logger.Error("未收到机器返回数据，已超时");
                    ResetTestState();
                    return;
                }

                // 5. 处理并显示测试结果
                statusLabel.Text = "正在处理测试数据...";
                DisplayTestResults(machineData);
                statusLabel.Text = "测试完成，数据已保存";
                logger.Info("测试流程完成，数据已处理并保存");

                #region mes操作
                //上传mes
                //获取token
                //上传数据
                

                #endregion

                // 自动进入下一轮（延迟1秒，给用户看结果的时间）
                Task.Delay(1000).ContinueWith(_ =>
                {
                    BeginInvoke(new Action(() =>
                    {
                        btnStartTest.PerformClick(); // 模拟点击开始按钮
                    }));
                });

            }
            catch (Exception ex)
            {
                statusLabel.Text = $"测试失败：{ex.Message}";
                MessageBox.Show($"错误：{ex.Message}", "操作失败",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                cts.Cancel(); // 取消所有等待任务
                cts.Dispose();
                _isWaitingForScan = false;
                _isProcessingTest = false;
                btnStartTest.Enabled = true;
                btnStopTest.Enabled = false;
            }
        }
        #endregion

        #region mes格式化

        #endregion

        #region 串口事件
        /// <summary>
        /// 连接到串口设备
        /// </summary>
        private async Task<bool> ConnectToSerialPort()
        {
            // 释放之前的连接
            if (_serialCommunicator != null)
            {
                _serialCommunicator.DataReceived -= OnSerialDataReceived;
                _serialCommunicator.StatusChanged -= OnSerialStatusChanged;
                _serialCommunicator.Dispose();
            }

            // 创建新的串口实例（使用已有串口库）
            _serialCommunicator = new SerialCommunicator(
                _portName,
                _baudRate,
                _parity,
                _dataBits,
                _stopBits
            );


            // 注册事件
            _serialCommunicator.DataReceived += OnSerialDataReceived;
            _serialCommunicator.StatusChanged += OnSerialStatusChanged;

            // 异步打开串口（避免UI卡顿）
            return await Task.Run(() =>
            {
                for (int i = 0; i < _currentSettings.SerialRetryCount; i++) // 最多重试3次
                {
                    if (_serialCommunicator.Open())
                        return true;
                    System.Threading.Thread.Sleep(1000);
                }
                return false;
            });
        }

        /// <summary>
        /// 等待扫描枪输入条码
        /// </summary>
        /// <param name="timeoutMs">超时时间(毫秒)</param>
        /// <summary>
        /// 等待键盘模式扫描枪输入
        /// 监听文本框的回车/换行符，判断扫描完成
        /// </summary>
        private async Task<bool> WaitForKeyboardScan(int timeoutMs, CancellationToken ct)
{
    var tcs = new TaskCompletionSource<bool>();
    KeyPressEventHandler keyHandler = null;
    CancellationTokenSource timeoutCts = null;

    try
    {
        // 创建超时的CancellationTokenSource
        timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
        timeoutCts.CancelAfter(timeoutMs); // 使用传入的超时时间

        keyHandler = (s, e) =>
        {
            if (e.KeyChar == '\r' || e.KeyChar == '\n')
            {
                txtBarcode.KeyPress -= keyHandler;
                tcs.TrySetResult(true);
            }
        };

        // 注册超时/取消回调
        using (timeoutCts.Token.Register(() =>
        {
            txtBarcode.KeyPress -= keyHandler;
            // 如果是超时则返回false，如果是外部取消则抛出异常
            if (ct.IsCancellationRequested)
                tcs.TrySetCanceled(ct);
            else
                tcs.TrySetResult(false);
        }))
        {
            txtBarcode.KeyPress += keyHandler;
            return await tcs.Task;
        }
    }
    finally
    {
        // 确保资源释放
        timeoutCts?.Dispose();
        txtBarcode.KeyPress -= keyHandler; // 双重保险移除事件
    }
}

/// <summary>
/// 等待机器返回测试数据（增加取消令牌支持）
/// </summary>
private async Task<string> WaitForMachineTestData(int timeoutMs, CancellationToken ct)
{
    string receivedData = string.Empty;
    var tcs = new TaskCompletionSource<string>();
    Action<string> tempDataHandler = null;
    CancellationTokenSource timeoutCts = null;

    try
    {
        // 创建关联了外部取消令牌的超时令牌源
        timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(ct);
        timeoutCts.CancelAfter(timeoutMs); // 设置超时时间

        tempDataHandler = (data) =>
        {
            // 只有在未取消的情况下才处理数据
            if (!timeoutCts.Token.IsCancellationRequested)
            {
                receivedData = data;
                tcs.TrySetResult(data);
            }
        };

        // 注册数据接收事件
        _serialCommunicator.DataReceived += tempDataHandler;

        // 注册取消/超时处理
        using (timeoutCts.Token.Register(() =>
        {
            // 移除事件订阅
            _serialCommunicator.DataReceived -= tempDataHandler;

            // 区分是外部取消还是超时
            if (ct.IsCancellationRequested)
                tcs.TrySetCanceled(ct); // 外部取消
            else
                tcs.TrySetResult(null); // 超时
        }))
        {
            // 等待结果
            return await tcs.Task;
        }
    }
    finally
    {
        // 确保资源释放和事件移除（双重保险）
        timeoutCts?.Dispose();
        _serialCommunicator.DataReceived -= tempDataHandler;
    }
}


        /// <summary>
        /// 串口数据接收事件处理
        /// </summary>
        private void OnSerialDataReceived(string data)
        {
            // 确保在UI线程处理
            if (InvokeRequired)
            {
                Invoke(new Action<string>(OnSerialDataReceived), data);
                return;
            }

            // 如果处于等待扫码状态，则视为扫描枪数据
            //if (_isWaitingForScan && string.IsNullOrEmpty(_scannedBarcode))
            //{
            //    _scannedBarcode = data.Trim(); // 保存条码
            //}
        }

        /// <summary>
        /// 串口状态变化事件处理
        /// </summary>
        private void OnSerialStatusChanged(string status)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<string>(OnSerialStatusChanged), status);
                return;
            }
            // 显示串口状态信息
            statusLabel.Text = $"串口状态：{status}";
        }

        /// <summary>
        /// 重置测试状态
        /// </summary>
        private void ResetTestState()
        {
            _isWaitingForScan = false;
            _isProcessingTest = false;

            // 清理取消令牌
            if (_cts != null)
            {
                _cts.Cancel();
                _cts.Dispose();
                _cts = null;
            }

            // 保持串口打开以便下次测试
            btnStartTest.Enabled = true;
            btnStopTest.Enabled = false;
        }
        // 新增：取消令牌源（用于手动停止测试）
        private CancellationTokenSource _cts;

        #endregion

        #region 其他按钮事件
        /// <summary>
        /// 停止测试按钮点击事件
        /// </summary>
        private void btnStopTest_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("确定要终止当前测试吗？", "确认",
                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                // 取消所有等待任务
                _cts?.Cancel();
                ResetTestState();
                statusLabel.Text = "测试已终止";
                //关闭串口
                _serialCommunicator.Close();
            }
        }

        //清零按钮
        private void clear_btn_Click(object sender, EventArgs e)
        {
            totalTest_txb.Text = "0";
            dispassItem_txb.Text = "0";
            passItem_txb.Text = "0";
            passRate_txb.Text = "0";
            count = 0;
            okcount = 0;
            nocount = 0;
        }

        #endregion
    }
}

